package org.kernely.quartz;

import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;

/**
 * This class manages the scheduling of the Kernely Quartz jobs.
 * This is a Singleton in order to ensure that there is only one instance of 
 * the Scheduler.
 */
public class KernelyQuartzScheduler {
	private static KernelyQuartzScheduler instance;
	private Scheduler scheduler;
	private ArrayList<JobDetail> scheduledJobs;
	private Log log = LogFactory.getLog(KernelyQuartzScheduler.class);
	
	/**
	 * Returns an existing instance of KernelyQuartzScheduler or a new one.
	 * @return An instance of the KernelyQuartzScheduler.
	 * @throws SchedulerException 
	 */
	public final static KernelyQuartzScheduler getInstance() throws SchedulerException {
		if(KernelyQuartzScheduler.instance == null) {
			KernelyQuartzScheduler.instance = new KernelyQuartzScheduler();
			KernelyQuartzScheduler.instance.getScheduler().addJobListener(new KernelyQuartzJobListener());
			KernelyQuartzScheduler.instance.scheduledJobs = new ArrayList<JobDetail>();
		} else{
	        LogFactory.getLog(KernelyQuartzScheduler.class).info("### KernelyQuartzScheduler: old scheduler detected");
		}
		LogFactory.getLog(KernelyQuartzScheduler.class).info("### KernelyQuartScheduler :"+KernelyQuartzScheduler.instance);
		return KernelyQuartzScheduler.instance;
	}
	
	private KernelyQuartzScheduler() throws SchedulerException {
        this.log.info("### KernelyQuartz : KernelyQuartzScheduler instantiated.");
        
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        this.scheduler = schedulerFactory.getScheduler();

        // Starts the Scheduler
        try {
			this.scheduler.start();
			this.log.info("### KernelyQuartzScheduler : Scheduler started.");
		} 
        catch (SchedulerException e) {
			e.printStackTrace();
        }
	}
	
	/**
	 * Gets a reference to the Scheduler.
	 * @return scheduler A reference to the Scheduler.
	 */
	public Scheduler getScheduler() {
		return this.scheduler;
	}
	
	public void schedulePeriodicJob(Class <? extends Job> jobClass, String jobName, int repeatCount, int repeatInterval) throws SchedulerException {	
		SimpleTrigger simpleTrigger = new SimpleTrigger(
			jobName,
			Scheduler.DEFAULT_GROUP,
			repeatCount,
			repeatInterval
		);
		
		JobDetail jobDetail = new JobDetail(jobName, Scheduler.DEFAULT_GROUP, jobClass);
		
		// We store repeat and interval data in the JobDetail
		JobDataMap map = new JobDataMap();
		map.put("count", repeatCount);
		map.put("interval", repeatInterval);

		jobDetail.setJobDataMap(map);
						
		jobDetail.addJobListener("KernelyQuartzJobListener");
		this.scheduledJobs.add(jobDetail);

		for (int i = 0; i < this.scheduledJobs.size() ; ++i){
			JobDetail jd = this.scheduledJobs.get(i);
			JobDataMap jobmap = jd.getJobDataMap();
			this.log.info(jd.getName());
			this.log.info(jobmap.getInt("count"));
			this.log.info(jobmap.getInt("interval"));
		}
	
		// We associate the Job and the Trigger into the Scheduler.
		this.scheduler.scheduleJob(jobDetail, simpleTrigger);
		
		this.log.info("### KernelyQuartzScheduler: jobName=" + jobName + " / " + "repeatCount=" + repeatCount + " / repeatInterval=" + repeatInterval);
	}

	public ArrayList<JobDetail> getScheduledJobs(){
		return scheduledJobs;
	}
}